// module name: rvcpu
// author: yangtao2019
// date: 2021.07.11

`timescale 1ns / 1ps

module rvcpu(
    input clk, 
    input rst,
    input [31:0] inst_32all,
    output[63:0] pc_now
);

    // ------------------declaritions------------------
    // pc-related
    //wire[63:0] pc_next, pc_now, pc_now_plus4, pc_beq;
    wire[63:0] pc_next, pc_now_plus4, pc_beq;
    wire[63:0] pc_jal, pc_jalr;

    // instruction-related
    // wire[31:0]  inst_32all;
    wire[6:0] opcode;
    wire[5:0] rs1;
    wire[5:0] rs2;
    wire[5:0] rsd;
    wire[6:0] funct7;
    wire[2:0] funct3;
    wire[63:0] immnum_64;
    assign opcode = inst_32all[6:0];
    assign rs1 = inst_32all[19:15];
    assign rs2 = inst_32all[24:20];
    assign rd  = inst_32all[11:7];
    assign fucnt7 = inst_32all[31:25];
    assign funct3 = inst_32all[14:12];
    

    // control signs
    wire Branch, MemRead, MemtoReg, ALUOp1, ALUOp0, MemWrite, ALUSrc, RegWrite, PCSrc1, PCSrc0;
    wire ALUNum1Sec1, ALUNum1Sec0;
    wire Jalx;
    wire ZeroSign;
    wire DoubleWd;
    

    // alu-related
    wire[3:0] alu_ctl;
    wire[63:0] alu_num1, alu_num2, alu_result;

    // registers-related
    wire[63:0] write_regdata;
    wire[63:0] read_regdata1, read_regdata2;

    // memory-related
    wire[63:0] read_memdata, read_memdataEXT, read_memdata_processed;
    wire[63:0] write_memdata;
    wire[63:0] MemtoReg_out;

    // ------------------instances and connections------------------
    // PC and related
    DFF#(.WIDTH(32)) pc(.clk(clk), .arst(rst), .D(pc_next), .Q(pc_now));
    four2twoMUX PCSrcMUX(.code({PCSrc1, PCSrc0}), .data_in0(pc_now_plus4), .data_in1(pc_beq),
                         .data_in2(pc_now+immnum_64), .data_in3((read_regdata1+immnum_64)&(~64'b1)), .data_out(pc_next));
    adder pc_adder(.num1(pc_now), .num2(64'd4), .num_out(pc_now_plus4));
    adder BranchAdder(.num1(pc_now), .num2(immnum_64<<0), .num_out(pc_beq));

    // instructions memory
    //rom#(.ADDR_LEN(7)) ins_mem(.addr(pc_now),.read_data(inst_32all)); 


    // controllers
    main_controller main_controller( .opcode(opcode),   .Branch(Branch), .MemRead(MemRead),
                                .MemtoReg(MemtoReg), .ALUOp1(ALUOp1), .ALUOp0(ALUOp0),
                                .MemWrite(MemWrite), .ALUSrc(ALUSrc), .RegWrite(RegWrite),
                                .ALUNum1Sec1(ALUNum1Sec1), .ALUNum1Sec0(ALUNum1Sec0),
                                .ZeroSign(ZeroSign), .Jalx(Jalx)
    );
    Double_CTL doubleCTL (.funct3(inst_32all[14:12]), .DoubleWd(DoubleWd));

    // Registers
    regfile registers(  .clk(clk), .read_addr1(rs1), .read_addr2(rs2),
                        .write_en(RegWrite), .write_addr(rd), .write_data(write_regdata),
                        .read_data1(read_regdata1), .read_data2(read_regdata2)
    );
    two2oneMUX MemReadDoubleWdMUX(  .code(DoubleWd), .data_in0(read_memdataEXT), .data_in1(read_memdata),
                                    .data_out(read_memdata_processed)
    );
    two2oneMUX JalxMUX(.code(Jalx), .data_in0(MemtoReg_out), .data_in1(pc_now_plus4), .data_out(write_regdata));

    // ALU and related
    ALU alu(.alu_ctl(alu_ctl), .num1(alu_num1), .num2(alu_num2), .num_out(alu_result), .ZeroSign(ZeroSign));
    ALU_CTL ALU_CTL0(.ALUOp({ALUOp1, ALUOp0}), .funct7and3({funct7[6], func3}), .alu_ctl(alu_ctl));
    two2oneMUX ALUSrcMUX(.code(ALUSrc), .data_in0(read_data2), .data_in1(immnum_64), .data_out(alu_num2));
    four2twoMUX ALUNum1MUX( .code({ALUNum1Sec1, ALUNum1Sec0}), .data_in0(read_regdata1), .data_in1(pc_next),
                            .data_in2(1'b0), .data_in3(1'b0), .data_out(alu_num1)
    );

    // data memory
    ram#(.ADDR_LEN(7)) data_mem(  .clk(clk), .read(MemRead), .write(MemWrite),
                                  .addr(alu_result), .read_data(read_memdata),
                                  .write_Double(read_regdata2),
                                  .DoubleWd(DoubleWd)
    );
    signEXT#(.WIDTH_in(32), .WIDTH_out(64)) MemReadEXT(.in(read_memdata), .out(read_memdataEXT));
    two2oneMUX MemtoRegMUX (.code(MemtoReg), .data_in0(alu_result), .data_in1(read_memdata_processed), .data_out(MemtoReg_out));
    

    // immediate number generator
    ImmGen immGen (.inst(inst_32all), .immNumEXT(immnum_64));

endmodule